package com.hzp.net.server;

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.util.Iterator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


@Slf4j
public class NioServer {

    static SelectorProvider provider = SelectorProvider.provider();
    private Selector selector = null;
    private ServerSocketChannel server;

    private ExecutorService executorService = Executors.newCachedThreadPool();


    private boolean start;

    public NioServer(Integer port) throws IOException {
        selector = provider.openSelector();
        server = provider.openServerSocketChannel();
        server.bind(new InetSocketAddress(port));
        this.start = true;
        server.configureBlocking(false);
        server.register(selector, SelectionKey.OP_ACCEPT);
        log.info("服务端启动成功！");
    }

    public static void main(String[] args) throws IOException {
        new NioServer( 888).init();
    }

    private void init(){

        while (!Thread.interrupted()) {
            try {
                selector.select();  //阻塞等待事件
                Iterator<SelectionKey> iterator = this.selector.selectedKeys().iterator();  // 事件列表 , key -> channel ，每个KEY对应了一个channel
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    iterator.remove();//移除当前key
                    if (key.isValid()) {
                        dispatch(key);  //分发事件
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void dispatch(SelectionKey key){
        if (key.isAcceptable()) {
            this.executorService.submit(new AcceptHandler(key));  //可以写，执行写事件
        } else if (key.isReadable()) {
            this.executorService.submit(new ReadHandler(key));  //可以写，执行写事件
        } else if (key.isWritable()) {
            this.executorService.submit(new WriteHandler(key));  //可以读。执行读事件
        }
    }


    private void close() {
        try {
            if (server != null) {
                server.close();
            }
            if (selector != null) {
                selector.close();
            }
            this.start = false;
            log.info("server closed!");
        } catch (IOException e) {
        }
    }

}
